package engine.render;

import engine.Displays;
import engine.GL;
import engine.render.buffer.TriBuffer;
import engine.render.buffer.TextBuffer;
import engine.res.Color;
import math.matrix.Matmath;
import math.matrix.mat4f;
import static engine.GL.*;
import java.nio.FloatBuffer;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import util.Util;

public class GLEngine 
{
    
    private mat4f matOrtho;
    private mat4f matProjection;
    private mat4f matRotation;
    private mat4f matTranslation;
    
    // VBO TEST #1
//    private int vboNormalID;
//    private int vboTexCoordID;
//    private int vboVertexID;
//    
//    private FloatBuffer bufNormal;
//    private FloatBuffer bufTexCoord;
//    private FloatBuffer bufVertex;
    
    // VBO TEST #2
//    private int vboID;
//    private FloatBuffer vbobuffer;
    
    public GLEngine(Displays display, float znear, float zfar) 
    {
        matOrtho = new mat4f();
        matProjection = new mat4f();
        matRotation = new mat4f();
        matTranslation = new mat4f();
        
        Matmath.calcOrtho(0, display.currentW(), 0, display.currentH(), -1, 1, matOrtho);
        Matmath.calcProjection(display.fov(), display.aspectRatio(), znear, zfar, matProjection);
        Matmath.setIdentity(matRotation);
        Matmath.setIdentity(matTranslation);
        
        enable(TEXTURE);
        enable(TEXTURE_2D);
        enable(DEPTH_TEST);
        enable(BLEND);
        enable(CULL_FACE);
        
        depthFunc(LEQUAL);
        blendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA);
        frontFace(CCW);
        cullFace(BACK);
        clearColor(Color.BLACK_TRANSPARENT);
        
        viewport(0, 0, display.currentW(), display.currentH());
        matrixMode(PROJECTION);
        loadMatrix(Matmath.IDENTITY);
        multMatrix(matProjection);
        matrixMode(MODELVIEW);
        loadMatrix(Matmath.IDENTITY);
        
        // VBO TEST #1
//        vboNormalID = genBufferObjID();
//        vboTexCoordID = genBufferObjID();
//        vboVertexID = genBufferObjID();
        // VBO TEST #2
//        vboID = genBufferObjID();
    }
    
    public void render(
            TriBuffer dim2, TriBuffer dim3, 
            TextBuffer textBuffer, 
            GLManager glManager)
    {
        clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT);
        matrixMode(MODELVIEW);
        loadMatrix(Matmath.IDENTITY);
        // Update matrices:
        Matmath.calcRotationMatXYZ(glManager.getRotations(), matRotation);
        Matmath.calcTranslation(glManager.getTranslation(), matTranslation);
        
        multMatrix(matRotation);
        multMatrix(matTranslation);
        
        glManager.bindColor(Color.WHITE);
        
        // VBO TEST #1
//        glManager.bindBitmap("ceiling");
//        
//        bindBufferObj(vboNormalID);
//        bufNormal = Util.getFloatBuf(dim3.getNormals());
//        bufferData(bufNormal, DYNAMIC_DRAW);
//        pointerDataNormal(0);
//        
//        bindBufferObj(vboTexCoordID);
//        bufTexCoord = Util.getFloatBuf(dim3.getTexCoords());
//        bufferData(bufTexCoord, DYNAMIC_DRAW);
//        pointerDataTexCoord(0);
//        
//        bindBufferObj(vboVertexID);
//        bufVertex = Util.getFloatBuf(dim3.getVertices());
//        bufferData(bufVertex, DYNAMIC_DRAW);
//        pointerDataVertex(0);
//        
//        enableClientState(NORMAL_ARRAY);
//        enableClientState(TEXTURE_COORD_ARRAY);
//        enableClientState(VERTEX_ARRAY);
//        
//        drawArrays(TRIANGLES, dim3.nTrisSent() * 3);
//        
//        disableClientState(NORMAL_ARRAY);
//        disableClientState(TEXTURE_COORD_ARRAY);
//        disableClientState(VERTEX_ARRAY);
//        
//        unbindAllBufferObjs();
//        
//        dim3.clearTris();
        
        // VBO TEST #2
        // { Vx, Vy, Vz, Nx, Ny, Nz, s, t, ... }
//        GL15.glBindBuffer(GL.ARRAY_BUFFER, vboID);
//        vbobuffer = Util.getFloatBuf(dim3.asFloatArray());
//        GL15.glBufferData(GL.ARRAY_BUFFER, vbobuffer, GL.DYNAMIC_DRAW);
////        GL11.glInterleavedArrays(GL11.GL_T2F_N3F_V3F, 0, vbobuffer);
//        GL15.glBindBuffer(GL.ARRAY_BUFFER, 0);
//        
//        GL15.glBindBuffer(GL.ARRAY_BUFFER, vboID);
//        GL11.glEnableClientState(COLOR_ARRAY);
//        GL11.glEnableClientState(TEXTURE_COORD_ARRAY);
//        GL11.glEnableClientState(NORMAL_ARRAY);
//        GL11.glEnableClientState(VERTEX_ARRAY);
//        
//        GL11.glDrawArrays(TRIANGLES, 0, dim3.nTrisSent() * 3);
//        
//        GL11.glDisableClientState(COLOR_ARRAY);
//        GL11.glDisableClientState(TEXTURE_COORD_ARRAY);
//        GL11.glDisableClientState(NORMAL_ARRAY);
//        GL11.glDisableClientState(VERTEX_ARRAY);
//        GL15.glBindBuffer(GL.ARRAY_BUFFER, 0);
//        
//        dim3.clearTris();
        
        // IMMEDIATE MODE
        dim3.renderTris(glManager);
        dim3.clearTris();
        
        matrixMode(PROJECTION);
        pushMatrix();
        loadMatrix(Matmath.IDENTITY);
        multMatrix(matOrtho);
        
        matrixMode(MODELVIEW);
        pushMatrix();
        loadMatrix(Matmath.IDENTITY);
        
        Shader temp = glManager.getShader();
        glManager.bindShader("basicTex");
        render2D(dim2, textBuffer, glManager);
        glManager.bindShader(temp);
        
        popMatrix();
        matrixMode(PROJECTION);
        popMatrix();
        
//        flush();
    }
    
//    private void render3D(TriBuffer dim3, GLManager glManager) 
//    {
//        glManager.bindColor(Color.WHITE);
//        dim3.renderTris(glManager);
//        dim3.clearTris();
//    }
    /*
        glManager.bindColor(Color.WHITE);
        
        Shader temp = glManager.getShader();
        glManager.bindShader("basic");
        disable(BLEND);
        depthFunc(LEQUAL);
        depthMask(true);
        colorMask(false, false, false, false);
        dim3.renderTris(glManager);
        
        glManager.bindShader(temp);
        enable(BLEND);
        blendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA);
        depthFunc(GEQUAL);
        depthMask(false);
        colorMask(true, true, true, true);
        dim3.renderTris(glManager);
        
        dim3.clearTris();
    */
    
    private void render2D(TriBuffer dim2, TextBuffer textBuffer, GLManager glManager) 
    {
        glManager.bindColor(Color.WHITE);
        dim2.renderTris(glManager);
        dim2.clearTris();
        
        glManager.bindColor(Color.WHITE);
        textBuffer.renderRasters(glManager);
        textBuffer.clearRasters();
    }
    
}
